package com.middlegroup.pay.utils;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.basic.DateConverter;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;

/**
 * @author SHUQWEI
 * @Pagke Name   com.middlegroup.pay.utils
 * @Description
 * @create 2019-08-13 14:12
 **/
@Slf4j
public class XmlUtils {
    private static final DomDriver DOM_DRIVER =
            new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_"));

    private static final DateConverter DATE_CONVERTER =
            new DateConverter("yyyy-MM-dd HH:mm:ss", null, TimeZone.getTimeZone("GMT+8"));

    /**
     * @param xml string
     * @param clz      the class which is target Bean
     * @param <T>
     * @return the bean parse from xml
     */
    public static <T> T xml2Bean(String xml, Class<T> clz) {
        // loading driver
        // xstream也业提供了json的转换驱动，JettisonMappedXmlDriver和JsonHierarchicalStreamDriver。
        XStream xStream = new XStream(DOM_DRIVER);
        // setup security configuration
        // setupDefaultSecurity to be removed after 1.5
        XStream.setupDefaultSecurity(xStream);
        xStream.allowTypesByWildcard(new String[]{"com.middlegroup.pay.**"});
        // register converter
        xStream.registerConverter(DATE_CONVERTER);
        // processing annotations
        xStream.processAnnotations(clz);
        // processing xml
        T t = (T) xStream.fromXML(xml);
        return t;
    }

    /**
     * return string of obj parsed by xstream.
     *
     * @param obj
     * @return
     */
    public static String toXml(Object obj) {
        XStream xStream = new XStream(DOM_DRIVER);
        // register converter
        xStream.registerConverter(DATE_CONVERTER);
        // processing annotations
        xStream.processAnnotations(obj.getClass());
        return xStream.toXML(obj);
    }

    /**
     * parse obj to xml and write to file.
     *
     * @param obj
     * @param filePath file path
     */
    public void outputFile(Object obj, String filePath) throws FileNotFoundException {
        XStream xStream = new XStream(DOM_DRIVER);
        // register converter
        xStream.registerConverter(DATE_CONVERTER);
        // processing annotations
        xStream.processAnnotations(obj.getClass());
        // create target file
        FileOutputStream fileOutputStream = new FileOutputStream(new File(filePath));
        // output
        xStream.toXML(obj, fileOutputStream);
    }


    /**
     * 使用Introspector，map集合成javabean
     *
     * @param map       map
     * @param beanClass bean的Class类
     * @return bean对象
     */
    public static <T> T mapToBean(Map<String, Object> map, Class<T> beanClass) {
        if (MapUtils.isEmpty(map)) {
            return null;
        }
        try {
            T t = beanClass.newInstance();
            BeanInfo beanInfo = Introspector.getBeanInfo(t.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                Method setter = property.getWriteMethod();
                if (setter != null) {
                    setter.invoke(t, map.get(property.getName()));
                }
            }
            return t;
        } catch (Exception ex) {
            log.error("Map对象bean转异常：{}", ex);
        }
        return null;
    }

    /**
     * 使用Introspector，对象转换为map集合
     *
     * @param beanObj javabean对象
     * @return map集合
     */
    public static Map<String, Object> beanToMap(Object beanObj) {
        if (null == beanObj) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(beanObj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if (key.compareToIgnoreCase("class") == 0) {
                    continue;
                }
                Method getter = property.getReadMethod();
                Object value = getter != null ? getter.invoke(beanObj) : null;
                if (value != null) {
                    map.put(key, value);
                }
            }
            return map;
        } catch (Exception ex) {
            log.error("bean对象转Map异常：{}", ex);
        }
        return null;
    }

}
